#[cfg(feature = "ssr")]
mod export;
#[cfg(feature = "ssr")]
mod import;
#[cfg(feature = "ssr")]
mod import_template;
#[cfg(feature = "ssr")]
mod process;
#[cfg(feature = "ssr")]
use crate::prelude::{Error, FieldType, Result};
#[cfg(feature = "ssr")]
use calamine::{Data, DataType};
#[cfg(feature = "ssr")]
pub use export::*;
#[cfg(feature = "ssr")]
pub use import::*;
#[cfg(feature = "ssr")]
pub use import_template::get_import_template;
#[cfg(feature = "ssr")]
pub use import_template::get_home_visit_import_template;
#[cfg(feature = "ssr")]
pub use process::{add_chunk, for_file};
use serde_json::Value;
use std::iter::successors;
#[cfg(feature = "ssr")]
pub(super) fn json_val_to_string(jval: &Value) -> String {
    match jval {
        Value::Null => "".to_owned(),
        Value::Bool(v) => {
            if *v {
                "1".to_owned()
            } else {
                "0".to_owned()
            }
        }
        Value::Number(v) => {
            if v.is_i64() {
                v.as_i64().unwrap_or(0).to_string()
            } else if v.is_u64() {
                v.as_u64().unwrap_or(0).to_string()
            } else {
                v.as_f64().unwrap_or(0.0).to_string()
            }
        }
        Value::String(v) => v.to_owned(),
        _ => jval.to_string(),
    }
}
#[cfg(feature = "ssr")]
pub(super) fn convert(data: &Data, tp: &FieldType) -> Result<Value> {
    match tp {
        FieldType::Bool => match data {
            Data::Int(v) => Ok(Value::Bool(*v > 0)),
            Data::Float(v) => Ok(Value::Bool(*v > 0.0)),
            Data::String(v) => Ok(Value::Bool(
                v == "1" || v.to_lowercase() == "t" || v.to_lowercase() == "true",
            )),
            Data::Bool(v) => Ok(Value::Bool(*v)),
            Data::Empty | Data::Error(_) => Ok(Value::Null),
            _ => Err(Error::from(format!("值{}转换为Bool失败", data))),
        },
        FieldType::Int8
        | FieldType::Int16
        | FieldType::Int32
        | FieldType::Int64
        | FieldType::UInt8
        | FieldType::UInt16
        | FieldType::UInt32
        | FieldType::UInt64 => match data {
            Data::Int(v) => Ok(Value::from(*v)),
            Data::String(v) => {
                if v.contains(".") {
                    let fv: f64 = v.parse()?;
                    Ok(Value::from(fv as i64))
                } else {
                    let v: i64 = v.parse()?;
                    Ok(Value::from(v))
                }
            }
            Data::Bool(v) => {
                let nv = if *v { 1_i64 } else { 0_i64 };
                Ok(Value::from(nv))
            }
            Data::Float(v) => Ok(Value::from(*v as i64)),
            Data::Empty | Data::Error(_) => Ok(Value::Null),
            _ => Err(Error::from(format!("值{}转换为Number失败", data))),
        },
        FieldType::Float32 | FieldType::Float64 | FieldType::Decimal(_, _) => match data {
            Data::Float(v) => Ok(Value::from(*v)),
            Data::Int(v) => Ok(Value::from(*v as f64)),
            Data::String(v) => {
                if v.contains(".") {
                    let fv: f64 = v.parse()?;
                    Ok(Value::from(fv))
                } else {
                    let iv: i64 = v.parse()?;
                    Ok(Value::from(iv))
                }
            }
            Data::Bool(v) => {
                let nv = if *v { 1_i64 } else { 0_i64 };
                Ok(Value::from(nv))
            }
            Data::Empty | Data::Error(_) => Ok(Value::Null),
            _ => Err(Error::from(format!("值{}转换为Number失败", data))),
        },
        FieldType::String(_) => match data {
            Data::Int(v) => Ok(Value::String(v.to_string())),
            Data::Float(v) => Ok(Value::String(v.to_string())),
            Data::String(v) => Ok(Value::String(v.to_string())),
            Data::Bool(v) => Ok(Value::String(if *v {
                "1".to_owned()
            } else {
                "0".to_owned()
            })),
            Data::DateTime(v) => Ok(Value::String(v.to_string())),
            Data::DateTimeIso(v) => Ok(Value::String(v.to_string())),
            Data::DurationIso(v) => Ok(Value::String(v.to_string())),
            Data::Empty | Data::Error(_) => Ok(Value::Null),
        },
        FieldType::Date => match data {
            Data::String(v) => {
                let fmt = if v.contains("/") {
                    "%Y/%m/%d"
                } else if v.contains("-") {
                    "%Y-%m-%d"
                } else if v.contains("年") {
                    "%Y年%m月%d日"
                } else {
                    "%Y%m%d"
                };
                let date_res = chrono::NaiveDate::parse_from_str(&v, fmt);
                if let Ok(date) = date_res {
                    let dstr = date.format("%Y-%m-%d").to_string();
                    Ok(Value::String(dstr))
                } else {
                    Err(Error::from(format!("值{}转换为Date失败", data)))
                }
            }
            Data::DateTime(_) | Data::DateTimeIso(_) => {
                if let Some(d) = data.as_date() {
                    let val = d.format("%Y-%m-%d").to_string();
                    Ok(Value::String(val))
                } else {
                    Ok(Value::Null)
                }
            }
            Data::Empty | Data::Error(_) => Ok(Value::Null),
            _ => Err(Error::from(format!("值{}转换为Number失败", data))),
        },
        FieldType::Datetime => match data {
            Data::String(v) => {
                let fmt = if v.contains("/") {
                    "%Y/%m/%d %H:%M:%S"
                } else if v.contains("-") {
                    if v.contains("T") {
                        "%Y-%m-%dT%H:%M:%S"
                    } else {
                        "%Y-%m-%d %H:%M:%S"
                    }
                } else if v.contains("年") {
                    "%Y年%m月%d日 %H时%M分%S秒"
                } else {
                    "%Y%m%d %H%M%S"
                };
                let date_res = chrono::NaiveDateTime::parse_from_str(&v, fmt);
                if let Ok(date) = date_res {
                    let dstr = date.format("%Y-%m-%dT%H:%M:%S").to_string();
                    Ok(Value::String(dstr))
                } else {
                    Err(Error::from(format!("值{}转换为Date失败", data)))
                }
            }
            Data::DateTime(_) | Data::DateTimeIso(_) => {
                if let Some(d) = data.as_date() {
                    let val = d.format("%Y-%m-%dT%H:%M:%S").to_string();
                    Ok(Value::String(val))
                } else {
                    Ok(Value::Null)
                }
            }
            Data::Empty | Data::Error(_) => Ok(Value::Null),
            _ => Err(Error::from(format!("值{}转换为Number失败", data))),
        },
    }
}
#[cfg(feature = "ssr")]
pub(super) fn column_name_to_number(name: &str) -> Result<u32> {
    let nlen = name.len();
    if nlen == 0 {
        return Err(Error::from("excel列名不能为空"));
    }
    for c in name.chars() {
        if !c.is_ascii_alphabetic() {
            return Err(Error::from(format!("excel列名{}无效", &name)));
        }
    }
    Ok(alpha_to_index(name.to_uppercase()))
}
#[cfg(feature = "ssr")]
pub(super) fn column_number_to_name(num: u32) -> Result<String> {
    if num < 1 || num > 16384 {
        let msg = format!("excel列名索引{}超出范围", num);
        return Err(Error::from(msg));
    }
    return Ok(index_to_alpha(num));
}

pub fn alpha_to_index<S>(alpha: S) -> u32
where
    S: AsRef<str>,
{
    const BASE_CHAR_CODE: u32 = 'A' as u32;
    // since we only allow up to three characters, we can use pre-computed
    /// powers of 26 `[26^0, 26^1, 26^2]`
    const POSITIONAL_CONSTANTS: [u32; 3] = [1, 26, 676];
    alpha
        .as_ref()
        .chars()
        .into_iter()
        .rev()
        .enumerate()
        .map(|(index, v)| {
            let vn = (v as u32 - BASE_CHAR_CODE) + 1;
            // 26u32.pow(index as u32) * vn
            POSITIONAL_CONSTANTS[index] * vn
        })
        .sum::<u32>()
}
#[cfg(feature = "ssr")]
pub fn index_to_alpha(index: u32) -> String {
    if index < 1 {
        panic!("Index cannot be less than one.")
    }
    const BASE_CHAR_CODE: u32 = 'A' as u32;
    // below code is based on the source code of `radix_fmt`
    successors(Some(index - 1), |index| match index / 26u32 {
        0 => None,
        n => Some(n - 1),
    })
    .map(|v| BASE_CHAR_CODE + (v % 26))
    .collect::<Vec<u32>>()
    .into_iter()
    .rev()
    .map(|v| char::from_u32(v).unwrap())
    .collect()
}
#[cfg(feature = "ssr")]
pub fn excel_cell_to_tuple(cell: &str) -> anyhow::Result<(u32, u32)> {
    // 分离列号和行号
    let mut col_str = String::new();
    let mut row_str = String::new();
    for c in cell.chars() {
        if c.is_ascii_uppercase() {
            col_str.push(c);
        } else {
            row_str.push(c);
        }
    }
    let row_str = row_str.trim();
    // 检查行号是否为空或不是数字
    if row_str.is_empty() || !row_str.chars().all(|c| c.is_digit(10)) {
        return Err(anyhow::anyhow!(
            "Invalid row number in cell address: {}",
            cell
        ));
    }
    // 将列字母转换为列号
    let mut col_num = 0;
    for c in col_str.chars() {
        col_num = col_num * 26 + (c as u32 - 'A' as u32 + 1);
    }
    // 将行号转换为数字
    let row_num = row_str
        .parse::<u32>()
        .map_err(|_| anyhow::anyhow!("Invalid row number in cell address: {}", cell))?;
    Ok((col_num, row_num))
}
